package edu.ncut.vod.hibernate.service.impl;

import java.util.List;

import org.springframework.beans.BeansException;
import org.springframework.beans.factory.config.BeanPostProcessor;

import edu.ncut.vod.exception.ExamException;
import edu.ncut.vod.hibernate.dao.ExamTypeDao;
import edu.ncut.vod.hibernate.dao.ExamUserDao;
import edu.ncut.vod.hibernate.dao.QuestionDao;
import edu.ncut.vod.hibernate.dao.StudentDao;
import edu.ncut.vod.hibernate.model.ExamType;
import edu.ncut.vod.hibernate.model.Question;
import edu.ncut.vod.hibernate.model.Student;
import edu.ncut.vod.hibernate.service.ExamService;

public class ExamServiceImpl implements ExamService,BeanPostProcessor {
    
    private ExamUserDao examUserDao;
    private StudentDao studentDao;
    private ExamTypeDao examTypeDao;
    private QuestionDao questionDao;

    public void setExamUserDao(ExamUserDao examUserDao) {
        this.examUserDao = examUserDao;
    }

    public void setStudentDao(StudentDao studentDao) {
        this.studentDao = studentDao;
    }

    public void setExamTypeDao(ExamTypeDao examTypeDao) {
        this.examTypeDao = examTypeDao;
    }

    public void setQuestionDao(QuestionDao questionDao) {
        this.questionDao = questionDao;
    }

    /**
     * 增加一个学生实例，对应为增加一条学生的记录
     *  @param stuNumber 学生学号。
     * @param name 学生学号。
     * @param classname 学生学号。
     * @param humanId 学生学号。
     * @param email 学生学号。
     * @param address 学生地址。
     * @param phone 学生电话。
     * @return 新增学生的主键
     */
    public int addStudent(String stuNumber, String name, String classname,
            String humanId, String email, String address, String phone)
            throws ExamException {
        debug("method addStudent in class ExamServiceImpl is called");
        
        try {
            Student student = new Student(stuNumber, name, classname, humanId,
                    email, address, phone);
            studentDao.save(student);
            return student.getStuId();
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExamException("添加学生时出现异常,请重试！");
        }
    }

    /**
     * 根据学生Id删除学生
     * @param id 需要删除的学生的主键。
     * @return 删除学生的记录数
     */
    public void deleteStudent(int id) throws ExamException {
        debug("method deleteStudent in class ExamServiceImpl is called");
        
        try {
            studentDao.delete(id);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExamException("删除学生时出现异常,请重试！");
        }
    }

    /**
     * 根据页码列出学生列表
     *  @param pageNo 页码 
     *  @return 列出的学生列表
     */
    public List<Student> listStudent(int pageNo) throws ExamException {
        debug("method listStudent in class ExamServiceImpl is called");
        
        try {
            return studentDao.findAllByPage(pageNo, STUDENT_PAGE_SIZE);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExamException("列出学生时出现异常,请重试！");
        }
    }

    /**
     * 增加一个试题，增加一条试题记录
     * @param quTitle 试题题目。
     * @param quHard 试题难度。
     * @param quScore 试题分数。
     * @param quAnswer 试题答案。
     * @param quType 试题类型。
     * @param selectOption 试题选项。
     * @param examTypeId 试题对应的考试类型
     * @return 新增试题的主键
     */
    public int addQuestion(String quTitle, String quHard, String quScore,
            String quAnswer, String quType, String selectOption, int examTypeId)
            throws ExamException {
        debug("method addQuestion in class ExamServiceImpl is called");
        
        try {
            ExamType examType = examTypeDao.get(examTypeId);
            if (examType == null) {
                throw new ExamException("不存在该考试类型，请重新选择");
            }
            Question question = new Question(examType.getTypeId(), quTitle,
                    quHard, quType, Integer.parseInt(quScore), quAnswer,
                    selectOption);
            questionDao.save(question);
            return question.getQuId();
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExamException("添加学生时出现异常,请重试！");
        }
    }

    /**
     * 根据试题ID删除试题
     * @param id 需要删除的试题的主键。
     */
    public void deleteQuestion(int id) throws ExamException {
        debug("method deleteQuestion in class ExamServiceImpl is called");
        
        try {
            questionDao.delete(id);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExamException("删除试题时出现异常,请重试！");
        }
    }

    /**
     * 新增考试类型
     * @param testName 新增的考试名称。
     * @param testTime 新增的考试时间
     * @return 新增的考试类型的ID
     */
    public int addExamType(String testName, String testTime)
            throws ExamException {
        debug("method addExamType in class ExamServiceImpl is called");
        
        ExamType et = new ExamType(testName, testTime);
        examTypeDao.save(et);
        return et.getTypeId();
    }

    /**
     * 获取所有考试类型
     * @return 所有考试类型
     */
    public List<ExamType> getAllExamType() throws ExamException {
        debug("method getAllExamType in class ExamServiceImpl is called");
        
        return examTypeDao.findAll();
    }

    /**
     * 根据考试类型ID删除考试类型
     * @param id 需要删除的考试类型的主键。
     */
    public void deleteExamType(int id) throws ExamException {
        debug("method deleteExamType in class ExamServiceImpl is called");
        
        try {
            examTypeDao.delete(id);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExamException("删除考试类型时出现异常,请重试！");
        }
    }

    /**
     * 根据页码列出试题列表
     * @param pageNo 页码 return 列出的试题列表
     */
    public List<Question> listQuestion(int pageNo) throws ExamException {
        debug("method listQuestion in class ExamServiceImpl is called");
        
        try {
            return questionDao.findAllByPage(pageNo, QUESTION_PAGE_SIZE);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExamException("列出考试试题时出现异常,请重试！");
        }
    }

    /**
     * 根据用户名和密码判断用户是否可以成功登录
     * @param user 登录用的用户名
     * @param pass 登录用的密码
     * @return 是否可以成功登录
     */
    public boolean adminLogin(String user, String pass) throws ExamException {
        debug("method adminLogin in class ExamServiceImpl is called");
        
        try {
            List result = examUserDao.findExamUserByNameAndPass(user, pass);
            if (result != null && result.size() > 0) {
                return true;
            }
            return false;
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExamException("系统管理员登录出现异常,请重试！");
        }
    }

    /**
     * 获取学生数量
     * @return 学生的个数
     */
    public int getStudentCount() throws ExamException {
        debug("method getStudentCount in class ExamServiceImpl is called");
        
        try {
            return (int) studentDao.getStudentCount();
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExamException("获取学生数量时出现异常,请重试！");
        }
    }

    /**
     * 获取试题数量
     * 
     * @return 试题的个数
     */
    public int getQuestionCount() throws ExamException {
        debug("method getQuestionCount in class ExamServiceImpl is called");
        
        try {
            return (int) questionDao.getQuestionCount();
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExamException("获取试题数量时出现异常,请重试！");
        }
    }

    /**
     * 根据每页记录数，总记录数获取总页数
     * @param count 总记录数
     * @param pageSize 每页显示的记录数
     * @return 计算得到的总页数
     */
    public int getPageCount(int count, int pageSize) {
        debug("method getPageCount in class ExamServiceImpl is called");
        
        return (count + pageSize - 1) / pageSize;
    }

    /**
     * 判断学生是否可以成功登录。
     * @param name 登录用的学生姓名
     * @param stuNumber 登录用的学号
     */
    public String studentLogin(String name, String stuNumber)
            throws ExamException {
        debug("method studentLogin in class ExamServiceImpl is called");
        
        try {
            List result = studentDao.findStudentByNameAndStuNumber(name,
                    stuNumber);
            if (result != null && result.size() > 0) {
                return name;
            }
            return null;
        } catch (Exception e) {
            throw new ExamException("学生登录出现异常，请重试！");
        }
    }

    /**
     * 根据考试类型ID获取下一个试题
     * @param alreadys 已经回答的试题ID
     * @param examTypeId 考试类型ID 
     * return 该考试类型的下一个试题
     */
    public Question getNextQuestion(List<Integer> alreadys, int examTypeId)
            throws ExamException {
        debug("method getNextQuestion in class ExamServiceImpl is called");
        
        try {
            ExamType examType = examTypeDao.get(examTypeId);
            if (examType == null) {
                throw new ExamException("不存在该考试类型，请重新选择");
            }
            int maxId = questionDao.getMaxId();
            REPEAT_TRY: while (true) {
                int randomId = (int) Math.round(Math.random() * maxId) + 1;
                // 如果已答题的数组不为空，判断获取的题是否已在已答题数组中
                if (alreadys != null) {
                    for (int alreadyId : alreadys) {
                        if (alreadyId == randomId) {
                            continue REPEAT_TRY;
                        }
                    }
                }
                Question question = null;
                // 如果获取题目出现异常,重新开始循环来获取下一题.
                try {
                    question = questionDao.findQuestionByExamType(randomId,
                            examType);
                } catch (Exception e) {
                    continue;
                }
                return question;
            }
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExamException("获取下一道试题时出现异常,请重试！");
        }
    }

    /**
     * 根据试题ID获取实体
     * @param id 试题ID 
     * return 该ID对应的试题
     */
    public Question getQuestionById(int id) throws ExamException {
        debug("method getQuestionById in class ExamServiceImpl is called");
        
        try {
            return questionDao.get(id);
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExamException("根据ID获取试题出错，请重试！");
        }
    }

    /**
     * 根据考试类型ID获取考试类型
     * @param typeId 考试类型ID 
     * return 该ID对应的考试类型名
     */
    public String getExamTypeName(int typeId) throws ExamException {
        debug("method getExamTypeName in class ExamServiceImpl is called");
        
        try {
            return examTypeDao.get(typeId).getTestTitle();
        } catch (Exception e) {
            e.printStackTrace();
            throw new ExamException("获取考试类型出现异常,请重试！");
        }
    }
    
    /**
     * this method is called on the bean just before this bean is removed from the container
     */
    public void destroy() {
        debug("destroy mothed in ExamServiceImpl object is called");
    }

    /**
     * this method is called on the bean immediately upon instantiation
     */
    public void setup() {
        debug("setup mothed in ExamServiceImpl object is called");
    }
    
    /*
     * the postProcessAfterInitialization() method is called immediately after initialization.
     * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessAfterInitialization(java.lang.Object, java.lang.String)
     */
    public Object postProcessAfterInitialization(Object arg0, String arg1)
            throws BeansException {
        debug("postProcessAfterInitialization method in ExamServiceImpl object is called");
        return null;
    }

    /*
     * The postProcessBeforeInitialization() method is called immediately prior to bean 
     * initialization (the call to afterPropertiesSet() and the bean’s custom initmethod).
     * @see org.springframework.beans.factory.config.BeanPostProcessor#postProcessBeforeInitialization(java.lang.Object, java.lang.String)
     */
    public Object postProcessBeforeInitialization(Object arg0, String arg1)
            throws BeansException {
        debug("postProcessBeforeInitialization method in ExamServiceImpl object is called");
        return null;
    }
    
    /*
     * print message on console
     */
    public void debug(String message){
        System.out.println(message);
    }
}
